import * as d3 from 'd3'
export { fnDrawMainChart }

//palette
let iColor = ['#06aacd', '#fb3781', '#f9b90f',"#fb3757","#f92946","#f17921","#f7b119","#2aafcc","#f2dbec","#f1cc21","#fc30a3"];
/**
 * frame - draw main chart
 * @param {div DOM} oDOM chart的div 容器
 * @param {svg DOM} oCanvas chart的svg 画布
 * @param {Object} item 绘制chart的 数据
 */
function fnDrawMainChart (oDOM,oCanvas,item) {
	oCanvas.innerHTML = '';	//清空画布
	let dataset = item.dataset;
	let width = oDOM.clientWidth,
		height = oDOM.clientHeight * 0.88;	//12% for title
	let	svg = d3.select(oCanvas)
	  			.attr('width',width)
	  			.attr('height',height);
	switch( item.kind ){
		case 'bar': 
			fnDrawBar(oDOM, svg, item);
			break;
		case 'text':
			fnDrawText(oDOM, svg, item);
			break;
		case 'ring':
			fnDrawRing(oDOM, svg, item);
			break;
		case 'line':
			fnDrawLine(oDOM, svg, item);
			break;
		case 'stack':
			fnDrawStack(oDOM, svg, item);
			break;
		case 'antenna':
			fnDrawAntenna(oDOM, svg, item);
			break;
	} 		
}

function fnDrawAntenna(oDOM, svg, oData){
    console.log(oData);
	svg.select('g').remove();	//clear canvas
	//data modify, adapt to axis-up & axis-down
	for(let antennaVal of oData.antennaVal) {
		(antennaVal.target_LP4 > 0) && (antennaVal.target_LP4 = -antennaVal.target_LP4);
		(antennaVal.LP4_LP2 > 0) && (antennaVal.LP4_LP2 = -antennaVal.LP4_LP2);
		(antennaVal.LP2_low > 0) && (antennaVal.LP2_low = -antennaVal.LP2_low);
	}
		
	let padding = { top:40, left:40 },
		svgWidth = oDOM.clientWidth, 
		svgHeight = oDOM.clientHeight * 0.9;
	let g = svg.append('g')
			.attr('class','gWrap-antenna')
			.attr(`transform`, `translate(${padding.left}, ${padding.top*0.5})`);
	let axisHeight = svgHeight - padding.top * 2,
		axisWidth = svgWidth - padding.left * 2;
		
	//data
	let xData = [],
		aUpNum = [],
		aLowNum = [];
	for(let oItem of oData.antennaVal){
 	  xData.push(oItem.xData);
 	   //up and low length number
		let nUpNum = oItem.HP4_HP2 + oItem.HP2_up,
			nLowNum = Math.abs(oItem.LP4_LP2) + Math.abs(oItem.LP2_low); 	 
		aUpNum.push(nUpNum);
		aLowNum.push(nLowNum);
	}
	//the maxYData for yAxis
	let nMaxYData = d3.max([...aUpNum, ...aLowNum]);
	function fnCoreLineYPos(d) {
		let nCoreBoxPointTol = d.target_HP4 + Math.abs(d.target_LP4),
			nCoreBoxPointDif = d.target_HP4 - Math.abs(d.target_LP4);
		if(nCoreBoxPointTol === 0 || nCoreBoxPointDif === 0) {
			return 0;
		}else {
			return nCoreBoxPointDif / nCoreBoxPointTol * 30;
		}
	}

	let x = d3.scaleBand()
			  .rangeRound([0, axisWidth])
			  .padding(0.7)
			  .domain(xData),
		y = d3.scaleLinear()
			  .rangeRound([axisHeight, 0])
			  .domain([-nMaxYData*1.25, nMaxYData*1.25]);	
	//draw axis
	let xAxis = d3.axisBottom(x);
	g.append('g')	
	 .classed('axis antenna-xAxis',true)
	 .attr('transform',`translate(0, ${axisHeight + padding.top*0.5})`)
	 .call(xAxis);
	//axis-style
	d3.select('.antenna-xAxis path').remove();
	d3.selectAll('.axis .tick line ').attr('stroke', '#dbe3ed');	 	
	
	//	vertical line
	g.append('g')
	 .attr('class', 'line-HP2_up')
	 .selectAll('rect')
	 .data(oData.antennaVal)
	 .enter()
	 .append('rect')
	 .attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5 - 1)
	 .attr('y', (d) => y((d.HP2_up + d.HP4_HP2)) - 30 )
	 .attr('width', 1)
	 .attr('height',d => {
	 	return (  y(d.LP4_LP2 + d.LP2_low) - y(d.HP2_up + d.HP4_HP2) + 60 )
	 })
	 .attr('fill', iColor[0]);	
	 
	//core box	***PS:core box height is fixed 60px***
	g.append('g')
	 .attr('class', 'coreBox')
	 .selectAll('rect')
	 .data(xData)
	 .enter()
	 .append('rect')
	 .attr('x', d => x(d))
	 .attr('y', axisHeight/2 - 30)
	 .attr('width', x.bandwidth())
	 .attr('height', 60)
	 .attr('fill','white')
	 .attr('stroke', iColor[0])
	 .attr('stroke-width', 2);		

	//draw cross table - middle line
	g.append('g')
	.attr('class', 'middleLine')
	.append('rect')
	.attr('x', padding.left)
	.attr('y', axisHeight/2 )
	.attr('width', axisWidth - padding.left*2 )
	.attr('height', 1)
	.attr('fill','white')
	.attr('stroke', '#000')
	.attr('opacity', 0.3);		 
	 
	// 4 line y-position 
	let fnHP2_upPos = d => y((d.HP2_up + d.HP4_HP2)) - 30,
		fnHP4_HP2Pos = d => y(d.HP4_HP2) - 30,
		fnLP4_LP2Pos = d => y(d.LP4_LP2) + 30,
		fnLP2_lowPos = d => y((d.LP4_LP2 + d.LP2_low)) + 30;

	//core box text
	g.append('g')	//text
		.attr('class', 'textValue coreBoxtextValue')
		.selectAll('text')
		.data(oData.antennaVal)
		.enter()
		.append('text')
		.attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5 )
		.attr('y', d => axisHeight/2 - 5 )
		.attr('dy', '-0.7em')
		.attr('dx', '-0.8em')
		.attr('font-size', '16px')
		.attr('text-anchor', 'start')
		.text(d => Math.abs(d.target_HP4) )
		.attr('fill', iColor[0]);	
	g.append('g')	//text
		.attr('class', 'textValue coreBoxtextValue')
		.selectAll('text')
		.data(oData.antennaVal)
		.enter()
		.append('text')
		.attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5 )
		.attr('y', d => axisHeight/2 + 30 )
		.attr('dy', '-0.7em')
		.attr('dx', '-0.8em')
		.attr('font-size', '16px')
		.attr('text-anchor', 'start')
		.text(d => Math.abs(d.target_LP4) )
		.attr('fill', iColor[0]);				
	
	//line - HP2_up
	g.append('g')
	 .attr('class', 'line-HP2_up')
	 .selectAll('rect')
	 .data(oData.antennaVal)
	 .enter()
	 .append('rect')
	 .attr('x', (d, i) => x(xData[i]) - x.bandwidth()*0.4)
	 .attr('y', d => fnHP2_upPos(d) )
	 .attr('width', x.bandwidth() * 1.8)
	 .attr('height', 4)
	 .attr('fill', iColor[1]);	
	g.append('g')	//text
	 .attr('class', 'textValue')
	 .selectAll('text')
	 .data(oData.antennaVal)
	 .enter()
	 .append('text')
	 .attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5 )
	 .attr('y', d => fnHP2_upPos(d) + (fnHP4_HP2Pos(d) - fnHP2_upPos(d))/2 )
	 .attr('dy', '-0.7em')
	 .attr('dx', '-0.8em')
	 .attr('font-size', '16px')
	 .attr('text-anchor', 'start')
	 .text(d => Math.abs(d.HP2_up) )
	 .attr('fill', iColor[1]);	
	 
	//line & text - HP4_HP2
	g.append('g')
	 .attr('class', 'line-HP4_HP2')
	 .selectAll('rect')
	 .data(oData.antennaVal)
	 .enter()
	 .append('rect')
	 .attr('x', (d, i) => x(xData[i]) - x.bandwidth()*0.2)
	 .attr('y', d => fnHP4_HP2Pos(d) )
	 .attr('width', x.bandwidth() * 1.4)
	 .attr('height', 2)
	 .attr('fill', iColor[2]);
	g.append('g')	//text
	 .attr('class', 'textValue')
	 .selectAll('text')
	 .data(oData.antennaVal)
	 .enter()
	 .append('text')
	 .attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5 )
	 .attr('y', d => fnHP4_HP2Pos(d) + (axisHeight/2-30 - fnHP4_HP2Pos(d))/2)	 
	 .attr('text-anchor','start')
	 .attr('dy','0.3em')
	 .attr('dx','-0.8em')
	 .attr('font-size', '16px')
	 .text(d => d.HP4_HP2)
	 .attr('fill', iColor[2]);
	 
	//core line
	g.append('g')
	 .attr('class', 'gCoreLine')
	 .selectAll('rect')
	 .data(oData.antennaVal)
	 .enter()
	 .append('rect')
	 .attr('x', d => x(d.xData))
	 .attr('y', d =>  axisHeight/2 - fnCoreLineYPos(d))
	 .attr('fill', iColor[0])
	 .attr('width', x.bandwidth())
	 .attr('height', 2);
	 
	//line - LP4_LP2
	g.append('g')
	 .attr('class', 'line-LP4_LP2')
	 .selectAll('rect')
	 .data(oData.antennaVal)
	 .enter()
	 .append('rect')
	 .attr('x', (d, i) => x(xData[i]) - x.bandwidth()*0.2)
	 .attr('y', (d) => fnLP4_LP2Pos(d) )
	 .attr('width', x.bandwidth() * 1.4)
	 .attr('height', 2)
	 .attr('fill', iColor[2]);
	g.append('g')	//text
	 .attr('class', 'textValue')
	 .selectAll('text')
	 .data(oData.antennaVal)
	 .enter()
	 .append('text')	
	 .attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5)	 
	 .attr('y', (d) => fnLP4_LP2Pos(d) - ( fnLP4_LP2Pos(d) - (axisHeight/2+30) )/2 )
	 .attr('dy', '0.3em')
	 .attr('dx', '-0.8em')
	 .attr('font-size', '16px')
	 .attr('text-anchor', 'start')
	 .text(d => Math.abs(d.LP4_LP2) )
	 .attr('fill', iColor[2]);
	 
	//line - LP2_low
	g.append('g')
	 .attr('class', 'line-LP2_low')
	 .selectAll('rect')
	 .data(oData.antennaVal)
	 .enter()
	 .append('rect')
	 .attr('x', (d, i) => x(xData[i]) - x.bandwidth()*0.4)
	 .attr('y', (d) => fnLP2_lowPos(d) )	
	 .attr('width', x.bandwidth() * 1.8)	
	 .attr('height', 4)
	 .attr('fill', iColor[1]);		
	g.append('g')	//text
	 .attr('class', 'textValue')
	 .selectAll('text')
	 .data(oData.antennaVal)
	 .enter()
	 .append('text')
	 .attr('x', (d, i) => x(xData[i]) + x.bandwidth()*0.5)
	 .attr('y', (d) => fnLP2_lowPos(d))
	 .attr('text-anchor', 'start')
	 .attr('dy', '1.3em')
	 .attr('dx', '-0.8em')
	 .attr('font-size', '16px')
	 .text(d => Math.abs(d.LP2_low))
	 .attr('fill', iColor[1]);		

	//chart fade in
	g.attr('opacity', 0).transition().duration(1500).attr('opacity', 1);
}

function fnDrawStack (oDOM, svg, { stackVal, xUnit, yUnit, legend, oRefLine }){
	let aStackColor = ['#06aacd','#73dcfc', '#f9b90f',"#fb3757","#f92946","#f17921","#f7b119","#2aafcc","#f2dbec","#f1cc21","#fc30a3"];
	svg.select('g').remove();	//clear canvas

	let padding = { top:50, left:50 },
		svgWidth = oDOM.clientWidth,
		svgHeight = oDOM.clientHeight * 0.9;
	let g = svg.append('g')
			.attr('class','gWrap-stack')
			.attr(`transform`, `translate(${padding.left + 10}, ${padding.top - 10})`);
	let axisHeight = svgHeight - padding.top * 2,
		axisWidth = svgWidth - padding.left * 2;	

	//legend.aName的前两个值为堆积柱形图的两块，所以需取出来，以生成stack；则legend.aName.slice(0,2) 
	let stack = null;
	let xData = [];
	if( Array.isArray(legend.aName) ) {//默认通过 lengend 读取 绘制 stack chart 的label
		stack = d3.stack().keys(legend.aName.slice(0,2));
	} else {// 若 legend 无法给出legend，转而通过 stackVal 获取 绘制chart的label
		let tempLegend = Object.keys(stackVal[0]);
		tempLegend.splice( Object.keys(stackVal[0]).indexOf('xData'), 1 );
		stack = d3.stack().keys( tempLegend );
	}
	let aSeries = stack(stackVal);
	for (let item of stackVal){
		xData.push(item.xData);
	}

	//get two refLine (is a array)
	let referenceLine = oRefLine.oTwoRefLine.aTwoRefLine;

	//get max value for yAxis
	let nMaxYData = d3.max(aSeries[aSeries.length-1],(d) => d[1]);
	if(referenceLine) {
		nMaxYData = d3.max(referenceLine.concat(nMaxYData));
	}

	let x = d3.scaleBand()
			.rangeRound([0, axisWidth])
			.padding(0.5)
			.domain(xData),
		y = d3.scaleLinear()
			.range([axisHeight, 0])
			.domain([0, nMaxYData*1.1]);	
	//draw Axis
	let xAxis = d3.axisBottom(x),
		yAxis = d3.axisLeft(y);
	yAxis.ticks(5);	
	g.append('g')	
	 .classed('axis xAxis',true)
	 .attr('transform',`translate(0, ${axisHeight})`)
	 .call(xAxis);
	g.append('g')
	 .classed('axis yAxis',true)
	 .call(yAxis);	

	//draw stack
	let gStackBar = g.append('g').attr('class', 'stackGroup');
    for(let i=0;i<aSeries.length;i++){
		gStackBar.selectAll('ract')
		 .data(aSeries[i])
		 .enter()
		 .append('rect')
		 .attr('x', (d,i) => x(xData[i]) )
		 .attr('y', y(0) )
		 .attr('width', x.bandwidth())
		 .attr('fill', aStackColor[i])
		 .transition()
		 .duration(2000)
		 .attr('y', (d,i) => y(d[1]) )
		  .attr('height', (d,i) => axisHeight - y(d[1] - d[0]) )
		 .attr('class', `stackBar`)
		 .attr('name', (d, i) => i);
	 }

	//axis style
	d3.selectAll('.xAxis .tick line').remove();
	d3.selectAll('.domain').attr('stroke','#dbe3ed');
	d3.selectAll('.yAxis line').attr('stroke','#dbe3ed');
	//axis unit
	g.append('g')
	 .attr('class', 'y-unit')
	 .append('text')
	 .attr('x', 0)
	 .attr('y', 0)
	 .attr('dx', '-1em')
	 .attr('dy', '-1em')
	 .text( yUnit );
	g.append('g')
	 .attr('class','x-unit')
	 .append('text')
	 .attr('x', axisWidth)
	 .attr('y', axisHeight)
	 .attr('dx', '-1em')
	 .attr('dy', '1.5em')
	 .text( xUnit );	

	//referenceLine
	if( referenceLine ) {  
		let aLine = referenceLine.sort( d3.ascending ); // sort reference line
		let refLineColor = [];
		if(aLine.length === 2 || aLine.length === 1) {
			refLineColor = ['#f1cc21', "#fc30a3"];
		}else {
			refLineColor = ["#2ec5bc",'#f1cc21', "#fc30a3","#fb3761","#2a8dcc","#fb3757","#f92946","#f17921"];
		}

		let gRefLine = g.append('g').attr('class', 'referenceLine');

		gRefLine.append('g')
		 .attr('class','refLine')
		 .selectAll('rect')
		 .data( aLine )
		 .enter()
		 .append('rect')
		 .attr('x', padding.left/2 )
		 .attr('y', d => y(d) )
		 .attr('width', axisWidth - padding.left )
		 .attr('height', 1.5)
		 .attr('opacity', 0)
		 .transition()
		 .duration(1500)
		 .attr('opacity', 1)		 
		 .attr('fill', (d, i) => refLineColor[i]);

		gRefLine.append('g')
			.attr('class', 'refText')
			.selectAll('text')
			.data( aLine )
			.enter()
			.append('text')
			.attr('x', axisWidth - padding.left/2 )
			.attr('dx', '0.5em')
			.attr('y', d => y(d) )
			.text(d => d)
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)
			.attr('text-anchor', 'start')
			.attr('fill', (d, i) => refLineColor[i])
			.attr('dy','0.3em')
			.attr('font-size','14px');
	}

	//value of every block
	for(let i = 0, l = aSeries.length; i < l; i++) {
		g.append('g')
			.attr('class', `stackBlockVal stackBlockVal${i}`)
			.selectAll('text')
			.data(aSeries[i])
			.enter()
			.append('text')
			.attr('x', (d,i) => x(xData[i]) )
			.attr('y', (d,i) => y(d[0] + (d[1] - d[0])/2) )
			.text( d => {
				if( Number.parseInt(d[1] - d[0]) === (d[1] - d[0])) {
					return (d[1] - d[0]) === 0 ? '' : d[1] - d[0];
				} else {
					return (d[1] - d[0]) === 0 ? '' : (d[1] - d[0]).toFixed(2);
				}
			}) 
			.attr('class', 'bi-show-value')
			.attr('transform', `translate(${x.bandwidth()/2},0)`)
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1);
	}	
}

function fnDrawLine (oDOM, svg, { lineData, xUnit, yUnit }){
	var LineColor = ['#06aacd','#73dcfc',"#2ec5bc","#fb3761","#2a8dcc","#fb3757","#f92946","#f17921","#f7b119","#2aafcc","#f2dbec","#f1cc21","#fc30a3"];	//palette
	svg.select('g').remove();	
	let padding = { top:50, left:50 },
		svgWidth = oDOM.clientWidth,
		svgHeight = oDOM.clientHeight * 0.9;
	let g = svg.append('g')
			.attr('class','gWrap-line')
			.attr(`transform`, `translate(${padding.left+10}, ${padding.top-10})`);
	let axisHeight = svgHeight - padding.top * 2,
		axisWidth = svgWidth - padding.left * 2;	
	
	//get the max yData for draw yAxis
	let valueList=[]
	for (let x in lineData.yData) {
		valueList=valueList.concat(lineData.yData[x])
	}
	let nMaxYData = d3.max( valueList )
	let x = d3.scaleBand()
			  .rangeRound([0, axisWidth])
			  .padding(0.6)
			  .domain(lineData.xData),
		y = d3.scaleLinear()
			  .range([axisHeight, 0])
			  .domain([0, nMaxYData*1.1]);	
			  
	//draw Axis
	let xAxis = d3.axisBottom(x),
		yAxis = d3.axisLeft(y);
	yAxis.ticks(5);		
	g.append('g')	
		.classed('axis xAxis',true)
		.attr('transform',`translate(0, ${axisHeight})`)
		.call(xAxis);
	g.append('g')
		.classed('axis yAxis',true)
		.call(yAxis);
	//axis style
	d3.selectAll('.xAxis .tick line').remove();
	d3.selectAll('.domain').attr('stroke','#dbe3ed');
	d3.selectAll('.yAxis line').attr('stroke','#dbe3ed');
	//axis unit
	g.append('g')
	 .attr('class', 'y-unit')
	 .append('text')
	 .attr('x', 0)
	 .attr('y', 0)
	 .attr('dx', '-1em')
	 .attr('dy', '-1em')
	 .text( yUnit );
	g.append('g')
	 .attr('class','x-unit')
	 .append('text')
	 .attr('x', axisWidth)
	 .attr('y', axisHeight)
	 .attr('dx', '-1em')
	 .attr('dy', '1.5em')
	 .text( xUnit );		 			
	
	//draw line
	let linePath = d3.line();
	linePath.x( (d, i) => x( lineData.xData[i] ) + x.bandwidth()/2 )
			.y( y );
	function drawLine(dataArray,color){
	g.append('g')
	 .append('path')
	 .attr('class', 'linePath')
	 .attr('d', linePath( dataArray))
	 .attr('opacity', 0)
	 .transition()
	 .duration(1500)
	 .attr('opacity', 1)	 
	 .attr('stroke-width', 2)
	 .attr('fill', 'none')
	 .attr('stroke', color);
	
	 //draw circle
	g.append('g')
	.attr('class', 'pointCircle')
	.selectAll('circle')
	.data( dataArray)
	.enter()
	.append('circle')
	.attr('cx', (d, i) => x( lineData.xData[i] ) + x.bandwidth()/2 )
	.attr('cy', y)
	.attr('r',3)
	.attr('opacity', 0)
	.transition()
	.duration(1500)
	.attr('opacity', 1)	 
	.attr('stroke', color)
	.attr('stroke-width', 2)
	.attr('fill', 'white');

	//line value
	g.append('g')
	 .attr('class', 'lineValue')
	 .attr('opacity', 1)
	 .selectAll('text')
	 .data( dataArray )
	 .enter()
	 .append('text')
	 .attr('x', (d, i) => x( lineData.xData[i] ))
	 .attr('y', y)
	 .text((d) => d)
	 .attr('fill', color)
	 .attr('font-size', '16px')
	 .attr('dy', '-0.5em');
	}
	
	let count=0;
	for(let x in lineData.yData){
		drawLine(lineData.yData[x],LineColor[count++])
	}
}

function fnDrawRing (oDOM, svg, { ringVal }){
	//当ring 为两块时， 用此颜色
	let aRingColor = ['#06aacd','#73dcfc', '#f9b90f',"#fb3757","#f92946","#f17921","#f7b119","#2aafcc","#f2dbec","#f1cc21","#fc30a3"];
	
	//让ring 为5块颜色时， 用此颜色
	var RingColor=['#9be8ff','#73dcfc','#36bee7','#19a6d1','#e4f7fd'];
	svg.select('g').remove();	
	let svgWidth = oDOM.clientWidth,
		svgHeight = oDOM.clientHeight;
	let nOuterRadius = d3.min([svgWidth, svgHeight]) / 2 * 0.6,
		nInnerRadius = nOuterRadius * 0.7;
	let pie = d3.pie().value( (d) => d.value );
	let pieData = pie( ringVal );
	let arcPath = d3.arc()
					.innerRadius( nInnerRadius )
					.outerRadius( nOuterRadius );
	let g = svg.append('g').attr('class', 'donut');
	
	let arcs = g.selectAll('g')
		.data( pieData )
		.enter()
		.append('g')
		.attr('transform', `translate( ${svgWidth/2}, ${svgHeight/2.2})`);
	
	var pos = d3.arc().innerRadius(nOuterRadius).outerRadius(nOuterRadius); 

	if (ringVal.length==5){// VoCA Dashboard 下绘制此chart
		//draw ring
		arcs.attr('transform', `translate( ${svgWidth/2}, ${svgHeight/2})`);
		
		arcs.append('path')
			.attr('d', (d) => arcPath(d) )
			.attr('fill', (d,i) => RingColor[i]);
	   
		//format1: labels may overlap 
		//在圆环上面添加value值
		arcs.append('g')
			.attr('class','xx_xx')
			.attr('transform', (d) => {
				let x = arcPath.centroid( d )[0]; //text - x position
				let y = arcPath.centroid( d )[1]; //text - y position
				return `translate(${x}, ${y})`;
			})
			.append('text')
			.text((d,i) => ringVal[i].value+'%')
			.attr('text-anchor','middle');

		//圆环外的文字
		arcs.append('g')
			.attr('transform', (d, i) => {
				let x = arcPath.centroid( d )[0] *1.7; //text - x position
				let y = arcPath.centroid( d )[1] *1.7; //text - y position
		 		if( i % 2 === 0 ) {	//邻行文字，错开
					y += 20;
		 		}
				return `translate(${x}, ${y})`;
			})
			.append('text')
			.text((d,i) => {	//将数据拆分为 需要显示的 字符串
				let name = ringVal[i].name.split('-')[0];

				let sliceStart = ringVal[i].name.indexOf('-') + 1,
					sliceEnd = ringVal[i].name.indexOf('cars');
				let carNums = ringVal[i].name.slice(sliceStart, sliceEnd);

				return name + ': ' + carNums;
			})
			.attr('fill','grey')
			.attr('font-size', '14px')
			.attr('class','label')
			.attr('text-anchor','middle');
	  
		//绘制 圆环至环外文字的连线
		arcs.append("line")  
			.attr('stroke','grey')  
			.attr("x1",function(d){  
				return arcPath.centroid(d)[0]*1.2;  
			})  
			.attr("y1",function(d){  
				return arcPath.centroid(d)[1]*1.2;  
			})  
			.attr("x2",function(d, i){  
				return arcPath.centroid(d)[0]*1.7;  
			})  
			.attr("y2",function(d, i){  
				let middleAngle = (d.endAngle - d.startAngle) / 2 + d.startAngle + 0.1;	//0.1 -> 因文字与midlleAngle与“差量”
				//判断环外文字 是否位于 圆环的偏下位置
				let isBelow = middleAngle >= Math.PI/2 && middleAngle <= Math.PI * 3/2 ;

				/**
				 * 双重判断：
				 * 1层判断：因为环外文字，需要“临近错开“,所以线的“长短不一”
				 * 2层判断：若文字位于 圆环的偏下位置， 线要指向 文字的“上部”
				 */
				if( i % 2 === 0) {
					return isBelow ? arcPath.centroid(d)[1]*1.7 + 10 : arcPath.centroid(d)[1]*1.7 + 20;
				} else {
					return isBelow ? arcPath.centroid(d)[1]*1.7 - 10 : arcPath.centroid(d)[1]*1.7;
				}
			});

	} else {// 其他Dashboard下绘制此chart
		//draw ring
		arcs.append('path')
			.attr('d', (d) => arcPath(d) )
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)
			.attr('fill', (d,i) => aRingColor[i]);

		arcs.append('text')	// text
			.attr('transform', (d) => {
				let x = arcPath.centroid( d )[0] * 1.62; //text - x position
				let y = arcPath.centroid( d )[1] * 1.46; //text - y position
				return `translate(${x}, ${y})`;
			})
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)
			// .attr('text-anchor', 'middle')
			.attr('fill', (d,i) => aRingColor[i])
			// .attr('font-size', '16px')
			.attr('class', 'bi-show-value')
			.text( (d,i) => ringVal[i].name + ':' + ringVal[i].value);
	}
}

function fnDrawText (oDOM, svg, { textVal }){
	svg.select('g').remove();
	let svgWidth = oDOM.clientWidth,
		svgHeight = oDOM.clientHeight,
		fontSize = svgHeight / 6;		
	
	let val = Number.parseInt(textVal);	//how many days
	Number.isNaN(val) ? (val = '0') : (val = val.toString());	//if no days ,return 0 days
	let g = svg.append('g');
	let text = g.append('text');
	g.attr('transform','translate(0,-30)');

	text.text( val )	//draw how many days
		.attr('x', svgWidth/2 )
		.attr('y', svgHeight/2.2 )
		.attr('opacity', 0)
		.transition()
		.duration(1500)
		.attr('opacity', 1)		
		.attr('fill', iColor[0])
		.attr('text-anchor','middle')
		.attr('font-size', fontSize );

	text.append('tspan')		// text - 'days'
		.text(' days')
		.attr('font-size', '14')
		.attr('fill', '#86949b');	
		
	text.append('tspan')
		.text('Accumulated work load of each set report')
		.attr('font-size', '14')
		.attr('fill', '#86949b')
		.attr('text-anchor', 'start')
		.attr('x', svgWidth/5 )
		.attr('y', svgHeight/1.7 );
	
	text.append('tspan')
		.text('from start date to end date.')
		.attr('font-size', '14')
		.attr('fill', '#86949b')
		.attr('text-anchor', 'start')
		.attr('x', svgWidth/5 )
		.attr('y', svgHeight/1.5 );		

}

function fnDrawBar (oDOM, svg, oData){
	svg.select('g').remove();
	let iColor = ['#06aacd', '#fb3781', '#f9b90f'];
	let padding = { top:50, left:50 },
		svgWidth = oDOM.clientWidth,
		svgHeight = oDOM.clientHeight * 0.9;
	let g = svg.append('g')
			.attr('class','gWrap-bar')
			.attr(`transform`, `translate(${padding.left + 10}, ${padding.top - 10})`);
	let axisHeight = svgHeight - padding.top * 2,
		axisWidth = svgWidth - padding.left * 2;
	
	//data of refLine relevant
	let oRefLine = oData.oRefLine;
	{//get the max yData for draw yAxis
		var aTempTotalData = oData.barData.yData
		oData.lineData.yData && (aTempTotalData=aTempTotalData.concat(oData.lineData.yData));
		oRefLine.nSingleRefLine && (aTempTotalData=aTempTotalData.concat(oRefLine.nSingleRefLine));
		oRefLine.oTwoRefLine.aTwoRefLine && (aTempTotalData=aTempTotalData.concat(oRefLine.oTwoRefLine.aTwoRefLine));
		oRefLine.oMultiRefLine.aMultiRefLine_1 && (aTempTotalData=aTempTotalData.concat(oRefLine.oMultiRefLine.aMultiRefLine_1));
		oRefLine.oMultiRefLine.aMultiRefLine_2 && (aTempTotalData=aTempTotalData.concat(oRefLine.oMultiRefLine.aMultiRefLine_2));
		oRefLine.oRefLine_MTD_YTD.MTD && (aTempTotalData=aTempTotalData.concat(oRefLine.oRefLine_MTD_YTD.MTD));
		oRefLine.oRefLine_MTD_YTD.YTD && (aTempTotalData=aTempTotalData.concat(oRefLine.oRefLine_MTD_YTD.YTD));
		oRefLine.oTwoRefLine.aTwoRefLine && (aTempTotalData=aTempTotalData.concat(oRefLine.oTwoRefLine.aTwoRefLine));
	
		var nMaxYData = d3.max( aTempTotalData ),
			nMinYData = d3.min(aTempTotalData.filter(function(val){
				return Number.parseFloat(val).toString() !== "NaN";
			}));	
	}
	
	let x = d3.scaleBand()
			  .rangeRound([0, axisWidth])
			  .padding(0.6)
			  .domain(oData.barData.xData);
	
	//做此判断的目的 ， 是为适配 qSensor = summary 时， color bar 的柱子高度过于趋近的情况。
	if( oData.barData.OKOrNOK === 'OK' ) {
		var y = d3.scaleLinear()
				.range([axisHeight, 0])
				.domain([Math.round(nMinYData * 0.99), 100]);
	}else {
		var	y = d3.scaleLinear()
			.range([axisHeight, 0])
			.domain([0, nMaxYData*1.1]);
	}

	//draw Axis
	let xAxis = d3.axisBottom(x),
		yAxis = d3.axisLeft(y);
		
	//对y轴刻度进行处理：当 y轴单位为"NOK"或“SET”时，y轴单位 需为整数，不能为小数。
	if(oData.yUnit === 'NOK' || oData.yUnit === 'Nok' || oData.yUnit === 'not' || oData.yUnit === 'SET' || oData.yUnit === 'Set' || oData.yUnit === 'set') {
		d3.max(oData.barData.yData) <= 5 ?  	// 当整数小于5时， y-axis-ticks 的个数不能大于5
			yAxis.ticks(d3.max(oData.barData.yData)) : yAxis.ticks(5);
		yAxis.tickFormat(d3.format(d3.format(".0f")));
	} else {
		yAxis.ticks(5);
	}

	g.append('g')	
	 .attr('transform',`translate(0, ${axisHeight})`)
	 .attr('class','axis xAxis')
	 .call(xAxis);
	g.append('g')
		.classed('axis yAxis',true)
		.call(yAxis);

	//axis style
	d3.selectAll('.xAxis .tick line').remove();
	d3.selectAll('.domain').attr('stroke','#dbe3ed');
	d3.selectAll('.yAxis line').attr('stroke','#dbe3ed');
	d3.selectAll('.xAxis .tick line').remove();

	{//when too many axis ticks text, auto-rotate(45deg)
		let ticksCharTotal = 0;//记录x轴ticks的字母汇总，当总字母个数超过阈值时，旋转tick
		for(let item of oData.barData.xData) {
			ticksCharTotal += Number(item.length);
		}
		if(ticksCharTotal > 34) {
			d3.selectAll('.xAxis text')
				.attr('transform', `rotate(45) translate(2, -8)`)
				.attr('text-anchor', 'start');
		}
	}

	//axis unit
	g.append('g')
	 .attr('class', 'y-unit')
	 .append('text')
	 .attr('x', 0)
	 .attr('y', 0)
	 .attr('dx', '-1em')
	 .attr('dy', '-1em')
	 .text( oData.yUnit );
	g.append('g')
	 .attr('class','x-unit')
	 .append('text')
	 .attr('x', axisWidth + 22)
	 .attr('y', axisHeight)
	 .attr('dx', '-1em')
	 .attr('dy', '1.5em')
	 .attr('text-anchor', 'middle')
	 .text( oData.xUnit );		 			
		
	// bar relevant	
	if( oData.barData ){	
		if( oData.barData.OKOrNOK === 'OK' ) {	//be used to color bar (ok & nok chart)
			let aRedMultiLine = oData.oRefLine.oMultiRefLine.aMultiRefLine_1,
				aYellowMultiLine = oData.oRefLine.oMultiRefLine.aMultiRefLine_2;	
			//draw bar
			g.append('g')
			 .attr('class', 'barElement')
			 .selectAll('rect')
			 .data(oData.barData.yData)
			 .enter()
			 .append('rect')
			 .classed('bar', true)
			 .attr('class', 'bar')
			 .attr('x', (d, i) => x(oData.barData.xData[i]) )
			 .attr('width', x.bandwidth())
			 .attr('y', axisHeight)
			 .transition()
			 .duration(2000)
			 .attr('y', y)
			 .attr('height', (d, i) =>  axisHeight - y(d) )
			 .attr('fill', (d, i) => {
			 	if(d > aYellowMultiLine[i]) {
			 		return iColor[0];
			 	}else if (d <= aYellowMultiLine[i] && d >= aRedMultiLine[i]) {
			 		return iColor[2];
			 	}else {
			 		return iColor[1];
			 	}
			 });
			// bar value text
			g.append('g')
			 .attr('class', 'barValue')
			 .selectAll('text')
			 .data(oData.barData.yData)
			 .enter()
			 .append('text')
			 .attr('x', (d, i) =>  x(oData.barData.xData[i]) )
			 .attr('dx', x.bandwidth()/2 )
			 .attr('dy', '-0.5em')
			 .attr('y', y)
			 .attr('opacity', 0)
			 .transition()
			 .duration(1500)
			 .attr('opacity', 1)		 
			 .text((d) => d )
			 .attr('class', 'bi-show-value');
				 
		}else if ( oData.barData.OKOrNOK === 'NOK' ) {
			let nRedRefLine = d3.max( oData.oRefLine.oTwoRefLine.aTwoRefLine ),
				nYellowRefLine = d3.min( oData.oRefLine.oTwoRefLine.aTwoRefLine );
				
			g.append('g')
			 .attr('class', 'barElement')
			 .selectAll('rect')
			 .data(oData.barData.yData)
			 .enter()
			 .append('rect')
			 .classed('bar', true)
			 .attr('class', 'bar')
			 .attr('x', (d, i) => x(oData.barData.xData[i]) )
			 .attr('width', x.bandwidth())
			 .attr('y', y(0))
			 .transition()
			 .duration(2000)
			 .attr('y', y)
			 .attr('height', (d, i) =>  axisHeight - y(d) )
			 .attr('fill', (d, i) => {
			 	if(d > nRedRefLine) {
			 		return iColor[1];
			 	}else if (d <= nRedRefLine && d >= nYellowRefLine) {
			 		return iColor[2];
			 	}else {
			 		return iColor[0];
			 	}
			 });
			// bar value text
			g.append('g')
			 .attr('class', 'barValue')
			 .selectAll('text')
			 .data(oData.barData.yData)
			 .enter()
			 .append('text')
			 .attr('x', (d, i) =>  x(oData.barData.xData[i]) )
			 .attr('dx', x.bandwidth()/2 )
			 .attr('dy', '-0.5em')
			 .attr('y', y)
			 .attr('opacity', 0)
			 .transition()
			 .duration(1500)
			 .attr('opacity', 1)		 
			 .text((d) => d )
			 .attr('class', 'bi-show-value');
		}else {
			//draw Bar
			g.append('g')
			 .attr('class', 'barElement')
			 .selectAll('rect')
			 .data(oData.barData.yData)
			 .enter()
			 .append('rect')
			//  .classed('bar', true)
			 .attr('class', 'bar')
			 .attr('x', (d, i) => x(oData.barData.xData[i]) )
			 .attr('width', x.bandwidth())
			 .attr('y', y(0))
			 .transition()
			 .duration(2000)
			 .attr('y', y)
			 .attr('height', (d, i) =>  axisHeight - y(d) )
			 .attr('fill', iColor[0]);	
			// bar value text
			g.append('g')
			 .attr('class', 'barValue')
			 .selectAll('text')
			 .data(oData.barData.yData)
			 .enter()
			 .append('text')
			 .attr('x', (d, i) =>  x(oData.barData.xData[i]) )
			 .attr('dx', x.bandwidth()/2 )
			 .attr('dy', '-0.5em')
			 .attr('y', y)
			 .attr('opacity', 0)
			 .transition()
			 .duration(1500)
			 .attr('opacity', 1)		 
			 .text((d) => d)
			 .attr('class', 'bi-show-value');			 
		}
	}
	
	//MTD Reference Line
	if( oRefLine.oRefLine_MTD_YTD.MTD ) {
		let gMTD_YTD_Line = g.append('g').attr('class', 'gMTDYTDreferenceLine');
		gMTD_YTD_Line.append('g')	//MTD - line
			.attr('class','MTDYTDRefLine')
			.append('line')
			.attr('x1', padding.left/2 )
			.attr('y1', y(oRefLine.oRefLine_MTD_YTD.MTD))
			.attr('x2', axisWidth - padding.left/2)
			.attr('y2', y(oRefLine.oRefLine_MTD_YTD.MTD))
			.attr('stroke-dasharray','5 2')
			.attr('stroke-width', '2')
			.attr('stroke','#999');
		gMTD_YTD_Line.append('g')	//text - 'MTD'
			.attr('class','MTDYTDRefLine')
			.append('text')
			.attr('x', axisWidth - padding.left/2)
			.attr('y', y(oRefLine.oRefLine_MTD_YTD.MTD))
			.text('MTD')
			.attr('fill','#999')
			.attr('text-anchor', 'start')			
			.attr('dy','0.3em')
			.attr('dx', '0.5em')
			.attr('font-size','14px');		
	}
	
	//YTD Reference Line
	if( oRefLine.oRefLine_MTD_YTD.YTD ) {
		let gMTD_YTD_Line = g.append('g').attr('class', 'gMTDYTDreferenceLine');
		gMTD_YTD_Line.append('g')	//YTD - line
			.attr('class','MTDYTDRefLine')
			.append('line')
			.attr('x1', padding.left/2 )
			.attr('y1', y(oRefLine.oRefLine_MTD_YTD.YTD))
			.attr('x2', axisWidth - padding.left/2)
			.attr('y2', y(oRefLine.oRefLine_MTD_YTD.YTD))
			.attr('stroke-dasharray','5 2')
			.attr('stroke-width', '2')
			.attr('stroke','#999');
		gMTD_YTD_Line.append('g')	//text - 'YTD'
			.attr('class','MTDYTDRefLine')
			.append('text')
			.attr('x', axisWidth - padding.left/2 )
			.attr('y', y(oRefLine.oRefLine_MTD_YTD.YTD))
			.text('YTD')
			.attr('fill','#999')
			.attr('text-anchor', 'start')			
			.attr('dy','0.3em')
			.attr('dx', '0.5em')
			.attr('font-size','14px');		
	}

	//draw singleLine
	if( oRefLine.nSingleRefLine ){
		let gSingleRefLine = g.append('g').attr('class', 'singleReferenceLine');
		gSingleRefLine.append('g')
			.attr('class','singleRefLine')
			.append('rect')
			.attr('x', padding.left/2 )
			.attr('width', axisWidth - padding.left  )
			.attr('y', y(oRefLine.nSingleRefLine))
			.attr('height', 1.5)
			.attr('opacity', 0)
			.transition()
			.duration(1500)			
			.attr('opacity', 1)
			.attr('fill', iColor[1]);

		gSingleRefLine.append('g')
			.attr('class', 'singleRefText')
			.append('text')
			.attr('x', axisWidth - padding.left/2 )
			.attr('y', y(oRefLine.nSingleRefLine) )
			.text( oRefLine.nSingleRefLine )
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)
			.attr('text-anchor', 'start')
			.attr('fill', iColor[1])
			.attr('dy','0.3em')
			.attr('dx', '0.5em')
			.attr('font-size','14px');
	}	

	//multiReferenceLine1
	if( oRefLine.oMultiRefLine.aMultiRefLine_1 ){
		//draw line
		g.append('g')
		 .attr('class','multiReferenceLine')
		 .selectAll('rect')
		 .data( oRefLine.oMultiRefLine.aMultiRefLine_1 )
		 .enter()
		 .append('rect')
		 .attr('x', ( d, i ) => x( oData.barData.xData[i] ))
		 .attr('y', (d) => y( d ))
		 .attr('width', x.bandwidth() * 1.4 )
		 .attr('height', 1.5)
		 .attr('fill', iColor[1])
		 .attr('opacity', 0)
		 .transition()
		 .duration(1500)
		 .attr('opacity', 1)		 
		 .attr('transform', `translate( ${-x.bandwidth()*0.2}, 0)`);


		//line value
		if( oData.barData.xData.length > 8) {
			g.append('g')
			.attr('class', 'multiReferenceLineValue')
			.selectAll('text')
			.data( oRefLine.oMultiRefLine.aMultiRefLine_1 )
			.enter()
			.append('text')
			.attr('x', (d, i) => x( oData.barData.xData[i])  )
			.attr('y', (d, i) => y(d) + 10 )
			.attr('font-size', '16px')
			.attr('dy', '0.4em')
			.attr('dx', '-0.2em')
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)		 
			.text( (d) => d )
			.attr('fill', iColor[1]);			
		} else {
			g.append('g')
			.attr('class', 'multiReferenceLineValue')
			.selectAll('text')
			.data( oRefLine.oMultiRefLine.aMultiRefLine_1 )
			.enter()
			.append('text')
			.attr('x', (d, i) => x( oData.barData.xData[i]) + x.bandwidth()*1.2 )
			.attr('y', (d, i) => y(d) )
			.attr('font-size', '16px')
			.attr('dy', '0.3em')
			.attr('dx', '0.2em')
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)		 
			.text( (d) => d )
			.attr('fill', iColor[1]);
		}
	}

	if( oRefLine.oMultiRefLine.aMultiRefLine_2 ){
		//draw line
		g.append('g')
		 .attr('class','multiReferenceLine')
		 .selectAll('rect')
		 .data( oRefLine.oMultiRefLine.aMultiRefLine_2 )
		 .enter()
		 .append('rect')
		 .attr('x', ( d, i ) => x( oData.barData.xData[i] ))
		 .attr('y', (d) => y( d ))
		 .attr('width', x.bandwidth() * 1.4 )
		 .attr('height', 1.5)
		 .attr('fill', iColor[2])
		 .attr('opacity', 0)
		 .transition()
		 .duration(1500)
		 .attr('opacity', 1)		 
		 .attr('transform', `translate( ${-x.bandwidth()*0.2}, 0)`);
		

		//line value
		if( oData.barData.xData.length > 8 ) {
			g.append('g')
			.attr('class', 'multiReferenceLineValue')
			.selectAll('text')
			.data( oRefLine.oMultiRefLine.aMultiRefLine_2 )
			.enter()
			.append('text')
			.attr('x', (d, i) => x( oData.barData.xData[i]) )
			.attr('y', (d, i) => y(d) + 10 )
			.attr('font-size', '16px')
			.attr('dy', '0.4em')
			.attr('dx', '-0.2em')
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)		 
			.text( (d) => d )
			.attr('fill', iColor[2]);
		} else {
			g.append('g')
			.attr('class', 'multiReferenceLineValue')
			.selectAll('text')
			.data( oRefLine.oMultiRefLine.aMultiRefLine_2 )
			.enter()
			.append('text')
			.attr('x', (d, i) => x( oData.barData.xData[i]) + x.bandwidth()*1.2 )
			.attr('y', (d, i) => y(d) )
			.attr('font-size', '16px')
			.attr('dy', '0.3em')
			.attr('dx', '0.2em')
			.attr('opacity', 0)
			.transition()
			.duration(1500)
			.attr('opacity', 1)		 
			.text( (d) => d )
			.attr('fill', iColor[2]);
		}

		

	}
	
	//two refLine
	if( oRefLine.oTwoRefLine.aTwoRefLine ) {
		//two refLine color, sort by red yellow
		let aTwoRefLineColor = ['#fc397f', '#fac63c'];
		let gRefLine = g.append('g').attr('class', 'twoRefLine');
		if( oRefLine.oTwoRefLine.isRedLineOnTop ) {
			gRefLine.append('g')		//refLine 
			 .attr('class','refLine')
			 .selectAll('rect')
			 .data( oRefLine.oTwoRefLine.aTwoRefLine )
			 .enter()
			 .append('rect')
			 .attr('x', padding.left/2 )
			 .attr('y', d => y(d) )
			 .attr('width', axisWidth - padding.left )
			 .attr('height', 1.5)
			 .attr('fill', (d, i) => {
				 let index = aTwoRefLineColor.length - 1;
				 return aTwoRefLineColor[index - i];
			 });
			gRefLine.append('g')		//refLine - text
				.attr('class', 'refText')
				.selectAll('text')
				.data( oRefLine.oTwoRefLine.aTwoRefLine )
				.enter()
				.append('text')
				.attr('x', axisWidth - padding.left/2 )
				.attr('y', d => y(d) )
				.attr('text-anchor', 'start')				
				.text(d => d)
				.attr('fill', (d, i) => {
					let index = aTwoRefLineColor.length - 1;
					return aTwoRefLineColor[index - i];
				})
				.attr('dy','0.3em')
				.attr('dx', '0.5em')
				.attr('font-size','14px');
		}else {
			gRefLine.append('g')		//refLine 
			 .attr('class','refLine')
			 .selectAll('rect')
			 .data( oRefLine.oTwoRefLine.aTwoRefLine )
			 .enter()
			 .append('rect')
			 .attr('x', padding.left/2 )
			 .attr('y', d => y(d) )
			 .attr('width', axisWidth - padding.left )
			 .attr('height', 1)
			 .attr('fill', (d, i) => aTwoRefLineColor[i]);
			 
			gRefLine.append('g')		//refLine - text
				.attr('class', 'refText')
				.selectAll('text')
				.data( oRefLine.oTwoRefLine.aTwoRefLine )
				.enter()
				.append('text')
				.attr('x', axisWidth - padding.left/2 )
				.attr('y', d => y(d) )
				.text(d => d)
				.attr('fill', (d, i) => aTwoRefLineColor[i] )
				.attr('text-anchor', 'start')				
				.attr('dy','0.3em')
				.attr('dx','0.5em')
				.attr('font-size','14px');			
		}
		gRefLine.attr('opacity', 0).transition().duration(1500).attr('opacity', 1);
	}

	//line relevant
	if( oData.lineData.yData ){
		//draw line
		let linePath = d3.line();
		linePath.x( (d, i) => x( oData.lineData.xData[i] ) + x.bandwidth()/2 )
				.y( y );
		g.append('path')
		 .attr('class', 'line')
		 .attr('d', linePath( oData.lineData.yData))
		 .attr('opacity', 0)
		 .transition()
		 .duration(1500)
		 .attr('opacity', 1)		 
		 .attr('stroke-width', 2)
		 .attr('fill', 'none')
		 .attr('stroke', iColor[1]);
		 
		//draw circle
		g.append('g')
		 .attr('class', 'pointCircle')
		 .selectAll('circle')
		 .data( oData.lineData.yData )
		 .enter()
		 .append('circle')
		 .attr('cx', (d, i) => x( oData.lineData.xData[i] ) + x.bandwidth()/2 )
		 .attr('cy', y)
		 .attr('r',5)
		 .attr('opacity', 0)
		 .transition()
		 .duration(1500)
		 .attr('opacity', 1)	 
		 .attr('stroke', iColor[1])
		 .attr('stroke-width', 2)
		 .attr('fill', 'white');
	 
		//line value
		g.append('g')
		 .attr('class', 'lineValue')
		 .selectAll('text')
		 .data( oData.lineData.yData )
		 .enter()
		 .append('text')
		 .attr('x', (d, i) => x( oData.lineData.xData[i] ))
		 .attr('y', y)
		 .text( d => d )
		 .attr('opacity', 0)
		 .transition()
		 .duration(1500)
		 .attr('opacity', 1)	 		 
		 .attr('fill', iColor[1])
		 .attr('font-size', '16px')
		 .attr('text-anchor', 'middle')
		 .attr('dx', x.bandwidth()/2 )
		 .attr('dy', '-0.5em');
	}
}